package com.gopay.bis.web.controller.ebank;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Enumeration;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.gopay.remote.cashier.bis.CashierBgNotifyRemoteService;
import com.gopay.remote.cashier.vo.CashierBgNotifyRespMsg;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.gopay.bis.common.util.BisPayCheckUtils;
import com.gopay.bis.common.util.IpAddrUtil;
import com.gopay.bis.common.util.SendSmsUtils;
import com.gopay.bis.common.util.TransUtils;
import com.gopay.bis.domain.order.OrderInfo;
import com.gopay.bis.service.bank.BankOrderService;
import com.gopay.common.Result;
import com.gopay.common.constants.bank.BankConstants;
import com.gopay.common.constants.bank.BisBankBusinessProd;
import com.gopay.common.constants.bank.BisBankInterfaceChannel;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.BankOrder;
import com.gopay.common.domain.bank.BaseMessage;
import com.gopay.common.domain.bank.external.BisExternalMessage;
import com.gopay.common.domain.bank.icbc.ebank.pay.IcbcB2cMessage;
import com.gopay.common.domain.bank.icbc.ebank.pay.res.PayB2CRes;
import com.gopay.common.domain.bank.icbc.ebank.pay.res.PayBankB2CRes;
import com.gopay.common.domain.bank.icbc.ebank.pay.res.PayOrderInfoB2CRes;
import com.gopay.common.domain.bank.icbc.ebank.pay.res.PaySubOrderB2CRes;
import com.gopay.common.domain.bank.icbc.ebank.pay.res.PaySubOrdersB2CRes;
import com.gopay.common.domain.proccode.ProcCodeInfo;
import com.gopay.common.proccode.DicProcCodeService;
import com.gopay.common.util.HttpTransport;
import com.gopay.common.util.RSAEncoderUtil;
import com.gopay.remote.bank.BankInteractRemoteService;

/**
 * 
 * IcbcB2CServerRes.java
 * 
 * @author WangHongFei
 */
@Controller
@Scope("prototype")
public class IcbcB2cServerRes {

	private static Log logger = LogFactory.getLog(IcbcB2cServerRes.class);
	@Resource(name = "bisConfig")
	protected Map<String, String> bisConfig;
	@Resource(name = "bankInteractService")
	private BankInteractRemoteService bankInteractService;
	@Resource(name = "dicProcCodeService")
	private DicProcCodeService dicProcCodeService;
	@Resource(name = "bisInteractExternalService")
	BankInteractRemoteService bisInteractExternalService;
	@Resource(name = "notifyCashier")
	private HttpTransport notifyCashier;
	@Resource(name = "cashierBgNotifyRemoteService")
	private CashierBgNotifyRemoteService cashierBgNotifyRemoteService;
	@Resource(name = "bankOrderService")
	private BankOrderService bankOrderService;
	@Resource(name = "smsConfig")
    private Map<String, String> smsConfig;
	
	@RequestMapping(value = "/IcbcB2cServerRes")
	protected ModelAndView execute(HttpServletRequest request,HttpServletResponse response) {
		logger.error("--------------- IcbcB2CServerRes bankback ---------------");
		// 打印请求参数
		this.displayRequestParameters(request, logger);
		String viewName = bisConfig.get("BIS.NOTIFY.CASHIER.FORWARD.FAIL");
		// 前台通知地址
		String notifyUrl = bisConfig.get("BIS.CLIENT.NOTIFY.CASHIER.BANK.RES");
		ModelAndView model = new ModelAndView();
		model.setViewName(viewName);
		if (StringUtils.isEmpty(request.getParameter("notifyData")) || StringUtils.isEmpty(request.getParameter("signMsg"))) {
			model.addObject("errorCode", ProcCodeConstants.PROC_CODE_100E7023);
			return model;
		}
		try {
			BaseMessage baseMessage = buildMessage(request);
			OrderInfo orderInfo = null;
			Result result = bankInteractService.bankBack(baseMessage);
			PayB2CRes res = (PayB2CRes) result.getModel("res");
			
			 // 验签通过进行后续处理
	        PayOrderInfoB2CRes orderInfoRes = res.getOrderInfo();
	        PaySubOrdersB2CRes orders = orderInfoRes.getSubOrders();
	        PaySubOrderB2CRes order = orders.getSubOrder();
	        PayBankB2CRes bankRes = res.getBankRes();
	        
			// 构建发往收银台的参数
			orderInfo = buildOrderInfo(res);
			orderInfo.setSign(sign(orderInfo));//  前台通知cashier签名数据
			logger.error(orderInfo.getOrderId() + " Referer: " + request.getHeader("Referer") + " Ip: " + IpAddrUtil.getRemoteRealIpAddr(request));
			if (result.isSuccess()) {
				if (result.isSuccess() && (Boolean) result.getDefaultModel()) {
					Map<String, String> param = (Map<String, String>) result.getModel("isNotifyCashier");
					param.put("sign", signRes(param));// 后台通知cashier签名数据
					String orderID = param.get("orderId");
					BankOrder bankOrder = bankOrderService.getBankOrderById(orderID);
					String gopayOrderId = bankOrder.getOrderId();
					// 根据订单号判断如果为外部平台的话走外部平台返回签名流程
					if (BisPayCheckUtils.checkExternalOrderID(gopayOrderId)) {
						BisExternalMessage bisMessage = new BisExternalMessage();
						bisMessage.setOrderId(param.get("orderId"));
						bisMessage.setAmount(new BigDecimal(param.get("amt")));
						if (param.get("payStatus").equals("00")) {
							bisMessage.setTradeState("1");
						} else {
							bisMessage.setTradeState("-1");
						}
						Result bisResult = bisInteractExternalService.bankBack(bisMessage);
						//如果银行返回成功并且签名成功设置成功页面
						if(param.get("payStatus").equals("00") && bisResult.isSuccess()){
							String redirectUrl = (String)bisResult.getModel("redirectUrl");
							viewName = "redirect:"+redirectUrl;
							// 通知银行返回
							if (orderInfo.getIsNotify()) {
								notifyBank(response,orderInfo,redirectUrl);
							}
						}
						model.setViewName(viewName);
						logger.error("外部平台订单["+gopayOrderId+"]处理成功，跳转地址： "+viewName);
						logger.error(param);
						logger.error("工行B2C处理成功：orderId=" + order.getOrderIdRes() + "|orderAmt="
					                + new BigDecimal(order.getAmountRes()) + "|orderStatus=" + bankRes.getTranStat() + "|描述="
					                + bankRes.getComment());
						return model;
					} else {
						// 通知cashier入账
                        String payStatus = param.get("payStatus"); // 交易状态
                        if (!("00".equals(payStatus))) {
                            // B2C交易失败不通知cashier,跳转到处理中页面
                            logger.error("IcbcB2CServerRes not notifyCashier " + orderID);
                            viewName = bisConfig.get("BIS.DEAL.FORWARD");
                        } else {
                            logger.error("IcbcB2CServerRes notifyCashier: " + param);
                            String resMsg = "";
                            try {
                                /*resMsg = notifyCashier.submit(param);
                                logger.error(orderID + "res =notifyCashier.submit(param):" + resMsg);*/ //生产优化10期 lx 2017-9-30 16:23:37
								CashierBgNotifyRespMsg respMsg= cashierBgNotifyRemoteService.callBgNotify(param);
								logger.error(orderID + "cashierBgNotifyRemoteService.callBgNotify(param) :" + respMsg.getRespMsg());

                                //if (!(resMsg.contains(ProcCodeConstants.PROC_CODE_100S1000))
                                //        && !(resMsg.contains(ProcCodeConstants.PROC_CODE_100E5111))) {
								/*if (resMsg.contains(ProcCodeConstants.PROC_CODE_000F3003)) {//只有乐观锁才置为96
								logger.error(bankOrder.getOrderId() + "bis ICBCB2C update status: 96");
                                    // 若交易状态不为交易成功,也不为重复处理，状态置为96自动对账处理
                                    bankOrderService.updateInAcctFail(bankOrder.getOrderId());
                                }*/
                                // 设置成功页面
                                viewName = bisConfig.get("BIS.NOTIFY.CASHIER.FORWARD");
                            } catch (Exception ec) {
                                logger.error(orderID + " IcbcB2CServerRes notifyCashier error: ", ec);
                                // 若通知cashier异常，状态置为96自动对账处理
                                //bankOrderService.updateInAcctFail(bankOrder.getOrderId());
                            }

                        }
						
						// 通知银行
						if (orderInfo.getIsNotify()) {
							notifyBank(response, orderInfo,null);
						}
					}
				} else if (!(Boolean) result.getDefaultModel()) {
					// 验签失败
					ProcCodeInfo procCodeInfo = dicProcCodeService.getProcCodeInfo(ProcCodeConstants.PROC_CODE_100E6040);
					orderInfo.setRetCode(ProcCodeConstants.PROC_CODE_100E6040);
					orderInfo.setRetMsg(procCodeInfo.getMessage());
					logger.error("平台订单["+orderInfo.getOrderId()+"]验签失败，跳转地址： "+viewName);
				} else if (result.isSuccess() && StringUtils.equals(ProcCodeConstants.PROC_CODE_100E6026,result.getResultCode())) {
					// 重复验签也返回成功页面，由收银台统一跳转
					viewName = bisConfig.get("BIS.NOTIFY.CASHIER.FORWARD");
					// 通知银行
					if (orderInfo.getIsNotify()) {
						notifyBank(response, orderInfo,null);
					}
				}
			} else {
				// 验签异常
				ProcCodeInfo procCodeInfo = dicProcCodeService.getProcCodeInfo(result.getResultCode());
				orderInfo.setRetCode(result.getResultCode());
				orderInfo.setRetMsg(procCodeInfo.getMessage());
				if(StringUtils.equals(result.getResultCode(), ProcCodeConstants.PROC_CODE_100E5079)){
                    SendSmsUtils.sendSmsErr(smsConfig.get("switch"), smsConfig.get("mobile"),"注意!!!订单金额不一致,银行:"+orderInfo.getBankName()+"orderId:"+orderInfo.getOrderId());
                }
			}
			model.setViewName(viewName);
			model.addObject("notifyUrl", notifyUrl);
			model.addObject("orderInfo", orderInfo);
			logger.error(orderInfo);
			logger.error(notifyUrl);
			logger.error("平台订单["+orderInfo.getOrderId()+"]处理成功，跳转地址： "+viewName);
			logger.error("工行B2C处理成功：orderId=" + order.getOrderIdRes() + "|orderAmt="
	                + new BigDecimal(order.getAmountRes()) + "|orderStatus=" + bankRes.getTranStat() + "|描述="
	                + bankRes.getComment());
		} catch (Exception e) {
			logger.error("IcbcB2cServerRes  error：", e);
			model.addObject("errorCode", ProcCodeConstants.PROC_CODE_100F1002);
			model.addObject("errorMsg", e.getMessage());
		}
		return model;
	}

	protected BaseMessage buildMessage(HttpServletRequest request) {
		String notifyData = request.getParameter("notifyData");
		String signMsg = request.getParameter("signMsg");
		IcbcB2cMessage message = new IcbcB2cMessage();
		// 银行码赋值
		message.setBank(BankConstants.BANK_LOGO_ICBC);
		message.setPlainMessage(notifyData);
		message.setSignMessage(signMsg);
        //银行业务产品00个人网银支付
        message.setBankBusProd(BisBankBusinessProd._00);
        // 银行接口通道信息 00: 直连
        message.setBankIntrChann(BisBankInterfaceChannel._00);
		return message;
	}

	protected OrderInfo buildOrderInfo(BaseMessage baseMessage) {
		PayB2CRes res = (PayB2CRes) baseMessage;
		if (res != null) {
			PaySubOrderB2CRes orderRes = res.getOrderInfo().getSubOrders().getSubOrder();
			OrderInfo orderInfo = new OrderInfo();
			orderInfo.setOrderId(orderRes.getOrderIdRes());
			orderInfo.setAmt(TransUtils.amountConvert2Yuan(orderRes.getAmountRes()));
			orderInfo.setNotifyNum("1");
			orderInfo.setPayStatus("00");
			orderInfo.setRetCode("00");
			orderInfo.setRetMsg("");
			orderInfo.setBankName("icbc");
			orderInfo.setIsNotify(true);
			return orderInfo;
		} else {
			return null;
		}
	}

	/**
	 * 通知银行处理结果
	 * 
	 * @param HttpServletResponse
	 * @param OrderInfo
	 * @return boolean
	 */
	protected boolean notifyBank(HttpServletResponse response,OrderInfo orderInfo,String bpsCallBackUrl) {
		StringBuffer paramters = new StringBuffer();
		paramters.append((String) bisConfig.get("BANK.PAY.CALLBACK.URL")).append("?");
		paramters.append("orderId=").append(orderInfo.getOrderId());
		paramters.append("&payStatus=").append(orderInfo.getPayStatus());
		paramters.append("&amt=").append(orderInfo.getAmt());
		paramters.append("&cardType=").append(orderInfo.getCardType());
		paramters.append("&retCode=").append(orderInfo.getRetCode());
		paramters.append("&bankName=").append(orderInfo.getBankName());
		String notifyMsg = paramters.toString();
		if(bpsCallBackUrl !=null && !bpsCallBackUrl.equals("")){
			notifyMsg = bpsCallBackUrl;
		}
		ServletOutputStream out = null;
		try {
			response.setContentType("text/html;charset=GBK");
			if ("icbc".equals(orderInfo.getBankName())) {
				logger.error("notifyBank" + orderInfo.getBankName()+ "send content: \n[" + notifyMsg + "]");
				response.addHeader("HTTP/1.1 200", "OK");
				response.addHeader("Server", "Apache/1.39");
				response.addHeader("Content-Length",String.valueOf(notifyMsg.length()));
				response.addHeader("Content-type", "text/html");
				response.setContentLength(notifyMsg.length());
				response.getWriter().write(notifyMsg);
				response.getWriter().flush();
				return true;
			}
			logger.error("notifyBank" + orderInfo.getBankName()+ "send content: \n[" + notifyMsg + "]");
			out = response.getOutputStream();
			out.print(notifyMsg);
			out.flush();
			return true;
		} catch (IOException e) {
			logger.error("notifyBank" + orderInfo.getBankName()+ "send error: ", e);
			return false;
		} finally {
			if (out != null) {
				try {
					out.close();
				} catch (IOException e) {
					logger.error("notifyBank close error: ", e);
					return false;
				}
			}
		}
	}
	
	public String sign(OrderInfo orderInfo) {
        StringBuffer sign = new StringBuffer();
        String orderId = orderInfo.getOrderId();
        String amt = orderInfo.getAmt();
        String retCode = orderInfo.getRetCode();
        String retMsg = orderInfo.getRetMsg();
        String payStatus = orderInfo.getPayStatus();
        String notifyNum = orderInfo.getNotifyNum();
        String cardType = orderInfo.getCardType();
        sign.append(orderId).append("|");
        sign.append(amt).append("|");
        sign.append(retCode).append("|");
        sign.append(retMsg).append("|");
        sign.append(payStatus).append("|");
        sign.append(notifyNum).append("|");
        sign.append(cardType);
        logger.error("bis通知cashier OrderInfo签名明文: " + sign.toString());
        try {
            return RSAEncoderUtil.sign(sign.toString());
        } catch (Exception e) {
            logger.error("bis通知cashier OrderInfo签名异常", e);
        }
        return "";
    }
    
    public String signRes(Map res) {
        StringBuffer sign = new StringBuffer();
        String orderId = (String)res.get("orderId");
        String amt = (String)res.get("amt");
        String retCode = (String)res.get("retCode");
        String retMsg = (String)res.get("retMsg");
        String payStatus = (String)res.get("payStatus");
        String notifyNum = (String)res.get("notifyNum");
        String cardType = (String)res.get("cardType");
        sign.append(orderId).append("|");
        sign.append(amt).append("|");
        sign.append(retCode).append("|");
        sign.append(retMsg).append("|");
        sign.append(payStatus).append("|");
        sign.append(notifyNum).append("|");
        sign.append(cardType);
        logger.error("bis通知cashier OrderInfo签名明文: " + sign.toString());
        try {
            return RSAEncoderUtil.sign(sign.toString());
        } catch (Exception e) {
            logger.error("bis通知cashier Map签名异常", e);
        }
        return "";
    }

	/**
	 * 输出请求参数
	 * 
	 * @param request
	 */
	@SuppressWarnings("rawtypes")
	protected void displayRequestParameters(HttpServletRequest request,
			Log logger) {
		for (Enumeration enumeration = request.getParameterNames(); enumeration.hasMoreElements();) {
			String eleName = (String) enumeration.nextElement();
			String eleValue = request.getParameter(eleName);
			if (logger != null) {
				logger.error("map key: [" + eleName + "]，value: [" + eleValue+ "]");
			}
		}
	}
}
